package com.fan.cachewebview.net

import android.content.Context
import android.os.Build
import android.text.TextUtils
import android.util.Log
import android.webkit.WebSettings
import com.fan.cachewebview.bean.WebResource
import com.fan.cachewebview.utils.AppUtils
import okhttp3.CacheControl
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
import java.net.HttpURLConnection
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * @description 网络加载具体实现
 * @date: 2022/3/1 11:12
 * @author: fan
 */
class OkHttpResourceLoader : ResourceLoadApi {

    private val HEADER_USER_AGENT = "User-Agent"
    private val DEFAULT_USER_AGENT = "CacheWebView"

    private var mContext: Context? = null

    constructor(context: Context) {
        mContext = context
    }


    override fun getResource(request: SourceRequest): WebResource? {
        var url = request.url
//        Log.d("fan123", "load url:$url")

        var isCacheByOkHttp = request.cacheable
        var client = OkHttpFactory[mContext!!]
        var cacheControl = getCacheControl(request.webViewCache, isCacheByOkHttp)
        var userAgent = request.userAgent
        if (TextUtils.isEmpty(userAgent)) {
            userAgent = DEFAULT_USER_AGENT
        }

        var locale = Locale.getDefault()
        var acceptLanguage = if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            locale.toLanguageTag()
        } else {
            locale.language
        }

        if (!acceptLanguage.equals("en-US", ignoreCase = true)) {
            acceptLanguage += ",en-US;q=0.9"
        }

        var requestBuilder = Request.Builder()
            .removeHeader(HEADER_USER_AGENT)
            .addHeader(HEADER_USER_AGENT, userAgent!!)
            .addHeader("X-Requested-With", mContext!!.packageName)
            .addHeader("Accept", "*/*")
            .addHeader("Accept-Language", acceptLanguage)
//            .addHeader("Upgrade-Insecure-Requests","1")

        var headers = request.headers
        if (headers != null && headers.isNotEmpty()) {
            for ((header, value) in headers) {
                if (!isNeedStripHeader(header)) {
                    requestBuilder.removeHeader(header)
                    requestBuilder.addHeader(header, value)
                }
            }
        }

        var okRequest = requestBuilder.url(url!!).cacheControl(cacheControl!!)
            .get().build()

        var response: Response? = null

        try {
            val remoteResource = WebResource()
            response = client!!.newCall(okRequest).execute()
            if (isInterceptorThisRequest(response)) {
                remoteResource.responseCode = response.code
                remoteResource.reasonPhrase = response.message
                remoteResource.isModified = response.code != HttpURLConnection.HTTP_NOT_MODIFIED
                val responseBody: ResponseBody? = response.body
                if (responseBody != null) {
                    remoteResource.originBytes = responseBody.bytes()
                }
                remoteResource.responseHeaders = AppUtils.generateHeadersMap(response.headers)
                return remoteResource
            }
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            response?.close()
        }


        return null
    }

    private fun isNeedStripHeader(headerName: String): Boolean {
        return (headerName.equals("If-Match", ignoreCase = true)
                || headerName.equals("If-None-Match", ignoreCase = true)
                || headerName.equals("If-Modified-Since", ignoreCase = true)
                || headerName.equals("If-Unmodified-Since", ignoreCase = true)
                || headerName.equals("Last-Modified", ignoreCase = true)
                || headerName.equals("Expires", ignoreCase = true)
                || headerName.equals("Cache-Control", ignoreCase = true))
    }

    private fun isInterceptorThisRequest(response: Response): Boolean {
        var code = response.code
        return !(code < 100 || code > 599 || (code in 300..399))
    }


    private fun getCacheControl(webViewCacheMode: Int, isCacheByOkHttp: Boolean): CacheControl? {
        return when (webViewCacheMode) {
            WebSettings.LOAD_CACHE_ONLY -> CacheControl.FORCE_CACHE
            WebSettings.LOAD_CACHE_ELSE_NETWORK -> {
                if (!isCacheByOkHttp) {
                    createNoStoreCacheControl()
                } else {
                    CacheControl.Builder().maxStale(Int.MAX_VALUE, TimeUnit.SECONDS).build()
                }
            }
            WebSettings.LOAD_NO_CACHE -> CacheControl.FORCE_NETWORK
            else -> if (isCacheByOkHttp) {
                CacheControl.Builder().build()
            } else createNoStoreCacheControl()
        }
    }

    private fun createNoStoreCacheControl(): CacheControl? {
        return CacheControl.Builder().noStore().build()
    }


}